﻿package com.net.http;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Map;

import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.json.JSONArray;
import org.json.JSONObject;

import com.cn.mobileproject.bean.User;

import android.util.Log;

/**
 * Wrap of org.apache.http.impl.client.DefaultHttpClient
 * @author lds
 */
public class HttpBaseClient {

    protected static final String TAG = "HttpBaseClient";
    protected final static String UTF8="UTF-8";
    protected final static String GBK="GBK";

    /** 服务端响应成功 */
    public static final int OK = 200;
    public static final int RESULT_OK =204;    
    /** 注册成功*/
    public static final int REGISTER_OK = 201;
    /** 服务端响应成功，但是无返回数据 */
    public static final int NOT_RESULT = 204;
    /** 输入不合法，提交的数据不是json 格式时，返回此状态码 */
    public static final int IPNUT_DATA_ERROR = 400;
    /** 清有请求的权限 */
    public static final int NOT_AUTHORIZED = 401;    
    public static final int AUTH_ERROR =403;    
    public static final int ERROR_404 = 404;
    /** 请求的方法不存在 */
    public static final int METHOND_NOT_FOUND = 405;
    /** 接口未实现 */
    public static final int INTERFACE_NOT_IMPLEMENTS = 501;
    //连接时间超时
    protected static final int CONNECTION_TIMEOUT_MS = 20 * 1000;
    //SOCKET连接时间超时
    protected static final int SOCKET_TIMEOUT_MS = 20 * 1000;
    //重新得到上限20
    public static final int RETRIEVE_LIMIT = 20;
    //重试时间3
    public static final int RETRIED_TIME = 0;
    protected DefaultHttpClient mClient;
    protected BasicHttpContext localcontext;
    protected boolean DEBUG = false;
 
    protected String sid;
  
    public HttpBaseClient() {
//    	 mClient = new DefaultHttpClient();
        prepareHttpClient();
    }
    
	/**
     * 设置代理
     * @param hostname the hostname (IP or DNS name)主机名
     * @param port the port number. -1 indicates the scheme default port.端端口
     * @param scheme  the name of the scheme. null indicates the default scheme
     */
    public void setProxy(String host, int port, String scheme) {
        HttpHost proxy = new HttpHost(host, port, scheme);  
//      mClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
    }
    
    /**
     * 移除代理
     */
    public void removeProxy() {
//       mClient.getParams().removeParameter(ConnRoutePNames.DEFAULT_PROXY);
    }

    /**
     * Setup DefaultHttpClient
     * Use ThreadSafeClientConnManager.
     * 设HttpClient参数
     */
    protected void prepareHttpClient() {
// 		  Create and initialize HTTP parameters  表示HTTP协议和框架参数集合
//        HttpParams params = new BasicHttpParams();
//        //设置每个连接最大的自然连接数
//        ConnManagerParams.setMaxTotalConnections(params, 100);
//        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
//        SchemeRegistry schemeRegistry = new SchemeRegistry();
//        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
//        schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
        mClient = new DefaultHttpClient();
//        new AuthScope(UAPConfiguration.getUAPServiceURL(), AuthScope.ANY_PORT);
//        mClient.setCredentialsProvider(new BasicCredentialsProvider());       
//        BasicScheme basicScheme = new BasicScheme();
//        localcontext = new BasicHttpContext();
//        localcontext.setAttribute("preemptive-auth", basicScheme);
    }
    
    public Response httpRequest(String url, String httpMethod) throws  HttpException   {    	
        return httpRequest(url,null,httpMethod);
    }
    
    protected HttpUriRequest createMethod(String httpMethod, URI uri,JSONObject jsonobject,File file,ArrayList<BasicNameValuePair> postParams) throws HttpException {
        return createMethod(httpMethod,uri,jsonobject);
    }
    
    protected HttpUriRequest createMethod(String httpMethod, URI uri) throws HttpException {
        return createMethod(httpMethod,uri);
    }
    
    public Response httpRequestArray(String url,JSONArray array, String httpMethod) throws HttpException   {    	
        URI uri = createURI(url);
        if(!DEBUG)Log.i(TAG, "Sending " + httpMethod + " request to " + url);
        HttpResponse response = null;
        Response res = null;
        HttpUriRequest method = null;
        method = createMethod(httpMethod, uri, array);
        setupHTTPConnectionParams(method);
        try {
            response = mClient.execute(method,localcontext);    
            res = new Response(response);
            
        } catch (SocketTimeoutException nte) {
            throw new HttpException(nte.getMessage(),nte);
        }catch (ClientProtocolException e) {
            throw new HttpException(e.getMessage(), e);
        } catch (IOException ioe) {
            throw new HttpException(ioe.getMessage(), ioe);
        }
        catch(RuntimeException e){
        	Log.e(TAG," httpRequest throw runtimeException");
        }
        if (response != null) {
            int statusCode = response.getStatusLine().getStatusCode();
            handleResponseStatusCode(statusCode, res);
        } else {
            throw new HttpException("response is null");
        }        
        return res;
    }

    public Response httpRequest(String url, JSONObject jsonobject,  String httpMethod) throws HttpException   {    	
        URI uri = createURI(url);
        if(!DEBUG)Log.i(TAG, "Sending " + httpMethod + " request to " + url);
        HttpResponse response = null;
        Response res = null;
        HttpUriRequest method = null;
        method = createMethod(httpMethod, uri, jsonobject);
        setupHTTPConnectionParams(method);
        try {
            response = mClient.execute(method,localcontext);    
            res = new Response(response);
            
        } catch (SocketTimeoutException nte) {
            throw new HttpException(nte.getMessage(),nte);
        }catch (ClientProtocolException e) {
            throw new HttpException(e.getMessage(), e);
        } catch (IOException ioe) {
            throw new HttpException(ioe.getMessage(), ioe);
        }
        catch(RuntimeException e){
        	Log.e(TAG," httpRequest throw runtimeException");
        }
        if (response != null) {
            int statusCode = response.getStatusLine().getStatusCode();
            handleResponseStatusCode(statusCode, res);
        } else {
            throw new HttpException("response is null");
        }        
        return res;
    }
    
    public Response httpRequest(String url, byte[] b,JSONObject json,String httpMethod) throws HttpException   {
    	  URI uri = createURI(url);
    	  if(!DEBUG)Log.i(TAG, "Sending " + httpMethod + " request to " + url);
          HttpResponse response = null;
          Response res = null;
          HttpUriRequest method = null;
          method = createMethod(httpMethod, uri, b);
          setupHTTPConnectionParams(method);
          try {
              response = mClient.execute(method,localcontext);    
              res = new Response(response);
              
          } catch (SocketTimeoutException nte) {
              throw new HttpException(nte.getMessage(), nte);
          }catch (ClientProtocolException e) {
              throw new HttpException(e.getMessage(), e);
          } catch (IOException ioe) {
              throw new HttpException(ioe.getMessage(), ioe);
          }
          catch(RuntimeException e){
          	Log.e(TAG," httpRequest throw runtimeException");
          }
          if (response != null) {
              int statusCode = response.getStatusLine().getStatusCode();
              handleResponseStatusCode(statusCode, res);
          } else {
              throw new HttpException("response is null");
          }        
          return res;
    }
    

    /**
     * CreateURI from URL string
     * 创建URI
     * @param url
     * @return request URI
     * @throws HttpException
     * Cause by URISyntaxException
     */
    protected URI createURI(String url) throws HttpException {
        URI uri;
        try {
            uri = new URI(url);
        } catch (URISyntaxException e) {
            Log.e(TAG, e.getMessage(), e);
            throw new HttpException("Invalid URL.");
        }
        return uri;
    }

    /**
     * Setup HTTPConncetionParams
     * 设置HTTP的连接参数,超时时间，重试，异常处理
     */
    protected void setupHTTPConnectionParams(HttpUriRequest method) {
        HttpConnectionParams.setConnectionTimeout(method.getParams(),CONNECTION_TIMEOUT_MS);
        HttpConnectionParams.setSoTimeout(method.getParams(), SOCKET_TIMEOUT_MS);
        //设置异常自动处理
//        mClient.setHttpRequestRetryHandler(requestRetryHandler);        
        method.addHeader("Accept-Encoding", "gzip, deflate");
        method.addHeader(new BasicHeader("COOKIE", User.JSESSIONID+"="+ sid ));
        Log.d(TAG,User.JSESSIONID + "=" + sid);
    }
    
    /*
     * 添加byte
     */
    protected HttpUriRequest createMethod(String httpMethod, URI uri,byte[] b) throws HttpException {
        HttpUriRequest method;
        //HttpPost
        if (httpMethod.equalsIgnoreCase(HttpPost.METHOD_NAME)) {
            HttpPost post = new HttpPost(uri);
            try {
	            if(b!=null){
	            	ByteArrayEntity byteArray = new ByteArrayEntity(b);
	            	post.setEntity(byteArray);
	            }
            }catch (Exception e) {
				e.printStackTrace();
			} 
            method = post;
        }
        else {
            method = new HttpGet(uri);
        }
        return method;
    }
    
    
    protected HttpUriRequest createMethod(String httpMethod, URI uri,JSONArray array) throws HttpException {
        HttpUriRequest method;
        
        //HttpPost
        if (httpMethod.equalsIgnoreCase(HttpPost.METHOD_NAME)) {
            HttpPost post = new HttpPost(uri);
            HttpEntity entity = null;
            
//            try {
            	if(array!=null){
            		
            		ArrayList<BasicNameValuePair> postData = new ArrayList<BasicNameValuePair>();
//                    for (Map.Entry<String, String> entry : map.entrySet()) {
                        postData.add(new BasicNameValuePair("dataJson", array.toString()));
//                    }
                    try {
                    	entity = new UrlEncodedFormEntity(postData,GBK);
    					post.setEntity(entity);
    				} catch (UnsupportedEncodingException e) {
    					e.printStackTrace();
    				}
            	}
            
            method = post;
        }
        
        else {
            method = new HttpGet(uri);
            Log.v(TAG, "createMethod:"+method.getMethod());
        }
        return method;
    }
    

    protected HttpUriRequest createMethod(String httpMethod, URI uri,JSONObject jsonobject) throws HttpException {
        HttpUriRequest method;
        
        //HttpPost
        if (httpMethod.equalsIgnoreCase(HttpPost.METHOD_NAME)) {
            HttpPost post = new HttpPost(uri);
            HttpEntity entity = null;
            
//            try {
            	if(jsonobject!=null){
            		
            		ArrayList<BasicNameValuePair> postData = new ArrayList<BasicNameValuePair>();
                        postData.add(new BasicNameValuePair("dataJson", jsonobject.toString()));
                    try {
                    	entity = new UrlEncodedFormEntity(postData, GBK);
    					post.setEntity(entity);
    				} catch (UnsupportedEncodingException e) {
    					e.printStackTrace();
    				}
            	}
            
            method = post;
        }
        else {
            method = new HttpGet(uri);
            Log.v(TAG, "createMethod:"+method.getMethod());
        }
        return method;
    }
    
    
    /**
     * 解析HTTP错误码
     */
    protected static String getCause(int statusCode) {
        String cause = null;
        switch (statusCode) {
        case NOT_RESULT:
        	cause=" 服务端响应成功，不过没有要返回的数据";
            break;
        case IPNUT_DATA_ERROR:
            cause = "400 输入不合法，提交的数据不是 json 格式时";
            break;
        case AUTH_ERROR:
        case ERROR_404:
        case NOT_AUTHORIZED:
            cause = "没有请求的权限";
            break;
        case METHOND_NOT_FOUND:
        	cause="请求的方法不存在";
        	break;
        case INTERFACE_NOT_IMPLEMENTS:
        	cause ="接口未实现";
        	break;
        default:
            cause = "";
        }
        return statusCode + ":" + cause;
    }

    protected void handleResponseStatusCode(int statusCode, Response res) throws HttpAuthException,HttpServerException, HttpException {
//    	Log.v(TAG,"statusCode:"+statusCode);
    	String msg = getCause(statusCode) + "\n";
        switch (statusCode) {
        case OK:
        case REGISTER_OK:
        case RESULT_OK:
            break;
        case IPNUT_DATA_ERROR:   
        case METHOND_NOT_FOUND:        
            throw new HttpException(msg + res.asString(), statusCode);            
        case NOT_AUTHORIZED:
        case AUTH_ERROR:
        case ERROR_404:
            throw new HttpAuthException(msg + res.asString(), statusCode);
        case INTERFACE_NOT_IMPLEMENTS:
            throw new HttpServerException(msg+ res.asString(), statusCode);
        default:
            throw new HttpException(msg + res.asString(), statusCode);
        }
    }

    public void setSid(String sid) {
		this.sid = sid;
	}
    
    public String getSid(){
    	return this.sid;
    }

	/**
     * 异常自动恢复处理, 使用HttpRequestRetryHandler接口实现请求的异常恢复
     */
    protected HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() {
        // 自定义的恢复策略
        public boolean retryRequest(IOException exception, int executionCount,HttpContext context) {
            // 设置恢复策略，在发生异常时候将自动重试N次
            if (executionCount >= RETRIED_TIME) {
                return false;
            }
            if (exception instanceof NoHttpResponseException) {
                return true;
            }
            if (exception instanceof SSLHandshakeException) {
                return false;
            }
            HttpRequest request = (HttpRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
            boolean idempotent = (request instanceof HttpEntityEnclosingRequest);
             if (!idempotent) {
                return true;
            }
            return false;
        }
    };
}